package com.android.ripplelivewallpaper;

import android.service.wallpaper.WallpaperService;
import android.view.SurfaceHolder;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Color;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.view.MotionEvent;

public class LiveWallpaperDemoService extends WallpaperService{
	RippleLiveWallpaper ripplelivewallpaper;
	@Override
    public Engine onCreateEngine() {
        ripplelivewallpaper = new RippleLiveWallpaper();
		// ripplelivewallpaper.Initialize();
		return ripplelivewallpaper;
    }
	
	//Create engine to run wallpaper
	private class RippleLiveWallpaper extends Engine implements Runnable{
	
		private Thread main_thread;
		private boolean thread_can_run;
		private SurfaceHolder surfaceholder;
		private Paint paint;
		private int screen_width, screen_height;	
		private Bitmap original_image, ripple_image;
		int image_width,image_height,half_width,half_height;
		
		int tmp_i,bound_a,bound_b;
		int touch_x,touch_y;
		int image_size;
		
		int ripplemap[];
		int texture[];
		int ripple[];
		int oldind,newind,mapind;
		int riprad;
		
		
		private int frame_count = 0;
		private int FPS = 0;
		private long frame_count_start_time = 0;
		
		public RippleLiveWallpaper(){
			// screen_width = context.getResources().getDisplayMetrics().widthPixels;
			// screen_height = context.getResources().getDisplayMetrics().heightPixels;
			
			paint = new Paint();
			surfaceholder = getSurfaceHolder();
			original_image = BitmapFactory.decodeResource(getResources(), R.drawable.lotus);
			image_width = original_image.getWidth();
			image_height = original_image.getHeight();		
			half_width = image_width>>1;
			half_height = image_height>>1;
			riprad=1;
			image_size = image_width * (image_height+2) * 2;
			ripplemap = new int[image_size];		
			ripple = new int[image_width*image_height];
			texture = new int[image_width*image_height];        
			oldind = image_width;
			newind = image_width * (image_height+3);
			original_image.getPixels(texture, 0, image_width, 0, 0, image_width, image_height);
		}
		
		@Override
		public void onCreate(SurfaceHolder surfaceHolder)
		{
			super.onCreate(surfaceHolder);
			setTouchEventsEnabled(true);
		}
		
		@Override
		public void onDestroy()
		{
			super.onDestroy();			
		}
		
		@Override
        public void onSurfaceCreated(SurfaceHolder holder) {
            super.onSurfaceCreated(holder);            
			main_thread = new Thread(this);
			main_thread.start();
			thread_can_run = true;			
        }
		
		@Override
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            super.onSurfaceDestroyed(holder);
            boolean retry = true;
			thread_can_run = false;
			do {
				try {
					main_thread.join();
					retry = false;
				} catch (InterruptedException e) {
					e.printStackTrace();
					// we will try it again and again...
				}
			}while(retry);
        }	
		
		public void Update(){
			newframe();
			ripple_image = Bitmap.createBitmap(ripple, image_width, image_height, Config.ARGB_8888);
			// ripple_image = Bitmap.createScaledBitmap(ripple_image, screen_width, screen_height, true);
		}
		
		public void Draw(Canvas canvas){
			paint.setColor(Color.WHITE);
			// canvas.drawRect(0, 0, screen_width, screen_height, paint);
			paint.setColor(Color.BLACK);		
			canvas.drawBitmap(original_image, 0, 0, paint);
			canvas.drawBitmap(ripple_image, 0, 0, paint);
			// canvas.drawText("FPS: " + FPS, screen_width - 50, 50, paint);
			// canvas.drawText("screen_width: " + screen_width, screen_width/2 - 50, 75, paint);
			// canvas.drawText("screen_height: " + screen_height, screen_width/2 - 50, 90, paint);
		}
		
		@Override
		public void onTouchEvent(MotionEvent event) 
		{	
			super.onTouchEvent(event);
			touch_x = (int)event.getX();
			touch_y = (int)event.getY();
			disturb(touch_x, touch_y);			
		}
		
		@Override
		public void run(){
			while(thread_can_run){			
				try{
				// Thread.sleep(20);
				}catch(Exception e){}			
				Canvas lockcanvas = null;
				lockcanvas = surfaceholder.lockCanvas();
				synchronized (surfaceholder) {
					if(lockcanvas != null){
						if(System.currentTimeMillis() - frame_count_start_time < 1000){
							frame_count ++;
						}else{
							FPS = frame_count;
							frame_count = 0;
							frame_count_start_time = System.currentTimeMillis();
						}
						Update();
						Draw(lockcanvas);
						
						try {
							if (lockcanvas != null) {
								surfaceholder.unlockCanvasAndPost(lockcanvas);
							}
						} catch (IllegalArgumentException exception) {
							exception.printStackTrace();
						}
					}
				}
			}
		}
		
		public void disturb(int touch_x, int touch_y) {
			for (int j=touch_y-riprad;j<touch_y+riprad;j++) {
				for (int k=touch_x-riprad;k<touch_x+riprad;k++) {
					if (j>=0 && j<image_height && k>=0 && k<image_width) {
						ripplemap[oldind+(j*image_width)+k] += 512;
					}
				}
			}
		}
		
		public void newframe() {
			//Toggle maps each frame
			tmp_i=oldind;
			oldind=newind;
			newind=tmp_i;

			tmp_i=0;
			mapind=oldind;
			for (int y=0;y<image_height;y++) {
				for (int x=0;x<image_width;x++) {
					short data = (short)((ripplemap[mapind-image_width]+ripplemap[mapind+image_width]+ripplemap[mapind-1]+ripplemap[mapind+1])>>1);
					data -= ripplemap[newind+tmp_i];
					data -= data >> 5;
					ripplemap[newind+tmp_i]=data;

					//where data=0 then still, where data>0 then wave
					data = (short)(1024-data);

					//offsets
					bound_a=((x-half_width)*data/1024)+half_width;
					bound_b=((y-half_height)*data/1024)+half_height;

				  
					//bounds check
					if (bound_a>=image_width) bound_a=image_width-1;
					if (bound_a<0) bound_a=0;
					if (bound_b>=image_height) bound_b=image_height-1;
					if (bound_b<0) bound_b=0;
				  

					ripple[tmp_i]=texture[bound_a+(bound_b*image_width)];			
					mapind++;
					tmp_i++;
				}
			}
		}
	}
}